#ifndef __UDP_PORT_H
#define __UDP_PORT_H
#include <string>
#include <vector>
#include <map>
#include <rtc_base/socket_address.h>
#include "base/event_loop.h"
#include "ice/ice_credentials.h"
#include "ice/ice_def.h"
#include "ice/candidate.h"
#include "base/async_udp_socket.h"
#include "ice/stun.h"

#include "base/network.h"
namespace xrtc
{
    class IceConnection;
    typedef std::map<rtc::SocketAddress, IceConnection *> AddressMap;
    class UDPPort : public sigslot::has_slots<>
    {
    public:
        UDPPort(EventLoop *el, const std::string &transport_name, IceCandidateComponent comopnent,
                IceParameters ice_params);
        ~UDPPort();
        std::string IceUfrag() { return ice_params_.ice_ufrag; }
        std::string IcePwd() { return ice_params_.ice_pwd; }
        int CreateIceCandidate(Network *network, int min_port, int max_port, Candidate &c);
        bool GetStunMessage(const char *data, size_t len, const rtc::SocketAddress &addr, std::unique_ptr<StunMessage> *out_msg, std::string *out_username);
        std::string ToString();
        void SendBindingErrorResponse(StunMessage *stun_msg, const rtc::SocketAddress &addr, int err_code, const std::string &reason);
        // 服务器收到客户端发送来的bindrequest 消息，由于服务器第一次收到客户端的消息，客户端的ip 地址相对于服务器是未知的地址，服务器可以通过该地址创建candidate
        sigslot::signal4<UDPPort *, const rtc::SocketAddress &, StunMessage *, const std::string &> signal_unknown_address;

        IceConnection *CreateConnection(const Candidate &candidate);
        IceConnection *GetConnection(const rtc::SocketAddress &addr);

        void CreateStunUsername(const std::string& remote_username,std::string* stun_attr_username);

        const std::string &TransactionName() { return transport_name_; }
        IceCandidateComponent Component() { return component_; }
        const rtc::SocketAddress& LocalAddr() {return local_addr_;}
        const std::vector<Candidate>& Candidates() {return candidates_;}

      int SendTo(const char *buf,size_t len,const rtc::SocketAddress& addr);
    private:
        void OnReadPacket(AsyncUdpSocket *socket, char *buf, size_t size, const rtc::SocketAddress &addr, int64_t ts);
        bool ParseStunUsername(StunMessage *stun_msg, std::string *local_ufrag, std::string *remote_ufrag);

    private:
        EventLoop *el_;
        std::string transport_name_;
        IceCandidateComponent component_;
        IceParameters ice_params_;
        int socket_ = -1;
        std::unique_ptr<AsyncUdpSocket> async_socket_;
        rtc::SocketAddress local_addr_;
        std::vector<Candidate> candidates_;
        AddressMap connections_;
    };
} // namespace xrtc

#endif